package io.github.doc.action.language.visitor;

import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiElement;
import io.github.doc.action.element.FileElement;
import io.github.doc.action.language.engine.TemplateEngine;
import io.github.doc.action.language.engine.VelocityTemplateEngine;
import io.github.doc.common.CommentType;
import io.github.doc.common.ConfigKey;
import io.github.doc.config.PluginSetting;
import io.github.doc.config.state.PluginSettingsState;
import io.github.doc.util.TemplateUtils;

/**
 * <p>Company: 深圳振瀚信息技术有限公司成都分公司 </p>
 * <p>Description: </p>
 *
 * @param <T> parameter
 * @author ZH.Team
 * @version 1.0.0
 * @email "mailto:ZH.Team@zhxx.com"
 * @date 2025.01.06 20:54
 * @since y.y.y
 */
public abstract class AbstractTemplateVisitor<T extends PsiElement, F> implements Visitor<T, F> {

    /**
     * Project
     */
    protected final Project project;

    /**
     * Template engine
     */
    private final TemplateEngine templateEngine;


    /**
     * Plugin setting
     */
    private final PluginSetting pluginSetting;

    /**
     * Abstract template visitor
     *
     * @param project project
     * @since y.y.y
     */
    public AbstractTemplateVisitor(Project project) {
        this.project = project;
        PluginSettingsState pluginSettingsState = PluginSettingsState.getInstance();
        this.pluginSetting = pluginSettingsState.getState();
        this.templateEngine = new VelocityTemplateEngine(pluginSettingsState);
        Assert.notNull(this.pluginSetting, "plugin setting not null");
    }

    /**
     * Generate template
     *
     * @param fileElement file element
     * @return the string
     * @since y.y.y
     */
    protected String generateTemplate(FileElement fileElement, CommentType commentType) {
        F factory = this.getElementFactory();
        Assert.notNull(factory, "element factory not null");
        String template = null;
        switch (commentType) {
            case CLASS -> template = this.getClassTemplate();
            case METHOD -> template = this.getMethodTemplate();
            case FIELD -> template = this.getFiledTemplate();
        }
        return this.templateEngine.render(template, fileElement);
    }

    /**
     * Gets class template *
     *
     * @return the class template
     * @since y.y.y
     */
    private String getClassTemplate() {
        String config = this.pluginSetting.getConfig(ConfigKey.CLASS_COMMENT);
        if (StrUtil.isNotBlank(config)) {
            return config;
        }
        return TemplateUtils.getTemplateString(ConfigKey.CLASS_COMMENT + ".vm");
    }

    /**
     * Gets method template *
     *
     * @return the method template
     * @since y.y.y
     */
    private String getMethodTemplate() {
        String config = this.pluginSetting.getConfig(ConfigKey.METHOD_COMMENT);
        if (StrUtil.isNotBlank(config)) {
            return config;
        }
        return TemplateUtils.getTemplateString(ConfigKey.METHOD_COMMENT + ".vm");
    }

    /**
     * Gets filed template *
     *
     * @return the filed template
     * @since y.y.y
     */
    private String getFiledTemplate() {
        String config = this.pluginSetting.getConfig(ConfigKey.FILED_COMMENT);
        if (StrUtil.isNotBlank(config)) {
            return config;
        }
        return TemplateUtils.getTemplateString(ConfigKey.FILED_COMMENT + ".vm");
    }
}
